package com.gitee.zhuyunlong2018.mybatisplusrelations.handler;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.gitee.zhuyunlong2018.mybatisplusrelations.binder.IBinder;
import com.gitee.zhuyunlong2018.mybatisplusrelations.exceptions.RelationHandlerException;

import java.util.Comparator;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Predicate;

/**
 * 关联处理器，用于一对一、一对多、多对多的不同场景关联查询
 *
 * @param <T>
 * @param <R>
 */
public interface IHandler<T, R> {


    /**
     * 关联副表查询构造器，使用方式如下，其中Dept为关联副表模型
     * <p>.query(wrapper -> wrapper.eq(Dept::getId, 1))
     */
    IHandler<T, R> query(Consumer<LambdaQueryWrapper<R>> lambdaWrapperFunc);

    /**
     * 基于内存的Stream副表内容处理过滤
     */
    IHandler<T, R> filter(Predicate<R> streamFilter);

    /**
     * 基于内存的Stream副表内容处理排序
     */
    IHandler<T, R> sorted(Comparator<R> streamComparator);

    /**
     * 设置关联模型数据，设置后，query()方法将失效，并且直接绑定关联模型，不进行数据表检索
     * <p>此方法仅限EntityBindOne使用
     * @param foreignEntity
     */
    default IHandler<T, R> setForeignData(R foreignEntity) {
        throw new RelationHandlerException("设置被关联模型数据错误");
    }

    /**
     * 设置关联模型数据，设置后，query()方法将失效，并且直接绑定关联模型，不进行数据表检索
     * <p>此方法为EntityBindMany、ListBindOne、ListBindMany等使用
     * @param foreignList
     */
    default IHandler<T, R> setForeignData(List<R> foreignList) {
        throw new RelationHandlerException("设置被关联模型数据错误");
    }

    /**
     * 深度绑定
     * 调用将获得一个新的binder，此binder主表为原binder的副表
     * 使用示例如下
     * <p>.deepWith(binder -> {
     * binder.bindOne(UserSkillVO::getSkill).end();
     * })
     */
    IBinder<T> deepWith(Consumer<IBinder<R>> binderConsumer);

    /**
     * 返回绑定器，调用此法方法一般为本次handler处理完毕，并且需要返回binder去构建新的关联handler
     */
    IBinder<T> binder();

    /**
     * 结束，一般为本次handler结束，并且不继续进行其他字段的关联操作，直接结束
     */
    void end();
}
